﻿// Decompiled with JetBrains decompiler
// Type: UnityEngine.InternalStaticBatchingUtility
// Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E6AE6B5A-2752-4B07-9528-C8B77C62CE79
// Assembly location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll
// XML documentation location: C:\Users\windys\Unity\2021.3.39f1c1\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.xml

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Rendering;

#nullable disable
namespace UnityEngine
{
  internal class InternalStaticBatchingUtility
  {
    private const int MaxVerticesInBatch = 64000;
    private const string CombinedMeshPrefix = "Combined Mesh";

    public static void CombineRoot(
      GameObject staticBatchRoot,
      InternalStaticBatchingUtility.StaticBatcherGOSorter sorter)
    {
      InternalStaticBatchingUtility.Combine(staticBatchRoot, false, false, sorter);
    }

    public static void Combine(
      GameObject staticBatchRoot,
      bool combineOnlyStatic,
      bool isEditorPostprocessScene,
      InternalStaticBatchingUtility.StaticBatcherGOSorter sorter)
    {
      GameObject[] objectsOfType = (GameObject[]) Object.FindObjectsOfType(typeof (GameObject));
      List<GameObject> gameObjectList = new List<GameObject>();
      foreach (GameObject gameObject in objectsOfType)
      {
        if ((!((Object) staticBatchRoot != (Object) null) || gameObject.transform.IsChildOf(staticBatchRoot.transform)) && (!combineOnlyStatic || gameObject.isStaticBatchable))
          gameObjectList.Add(gameObject);
      }
      InternalStaticBatchingUtility.CombineGameObjects(gameObjectList.ToArray(), staticBatchRoot, isEditorPostprocessScene, sorter);
    }

    private static uint GetMeshFormatHash(Mesh mesh)
    {
      if ((Object) mesh == (Object) null)
        return 0;
      uint meshFormatHash = 1;
      int vertexAttributeCount = mesh.vertexAttributeCount;
      for (int index = 0; index < vertexAttributeCount; ++index)
      {
        VertexAttributeDescriptor vertexAttribute = mesh.GetVertexAttribute(index);
        uint num = (uint) (vertexAttribute.attribute | (VertexAttribute) ((int) vertexAttribute.format << 4) | (VertexAttribute) (vertexAttribute.dimension << 8));
        meshFormatHash = meshFormatHash * 2654435761U + num;
      }
      return meshFormatHash;
    }

    private static GameObject[] SortGameObjectsForStaticBatching(
      GameObject[] gos,
      InternalStaticBatchingUtility.StaticBatcherGOSorter sorter)
    {
      gos = ((IEnumerable<GameObject>) gos).OrderBy<GameObject, bool>((Func<GameObject, bool>) (g => InternalStaticBatchingUtility.StaticBatcherGOSorter.GetScaleFlip(g))).ThenBy<GameObject, long>((Func<GameObject, long>) (g => sorter.GetMaterialId(InternalStaticBatchingUtility.StaticBatcherGOSorter.GetRenderer(g)))).ThenBy<GameObject, int>((Func<GameObject, int>) (g => sorter.GetLightmapIndex(InternalStaticBatchingUtility.StaticBatcherGOSorter.GetRenderer(g)))).ThenBy<GameObject, uint>((Func<GameObject, uint>) (g => InternalStaticBatchingUtility.GetMeshFormatHash(InternalStaticBatchingUtility.StaticBatcherGOSorter.GetMesh(g)))).ThenBy<GameObject, long>((Func<GameObject, long>) (g => sorter.GetRendererId(InternalStaticBatchingUtility.StaticBatcherGOSorter.GetRenderer(g)))).ToArray<GameObject>();
      return gos;
    }

    public static void CombineGameObjects(
      GameObject[] gos,
      GameObject staticBatchRoot,
      bool isEditorPostprocessScene,
      InternalStaticBatchingUtility.StaticBatcherGOSorter sorter)
    {
      Matrix4x4 matrix4x4 = Matrix4x4.identity;
      Transform staticBatchRootTransform = (Transform) null;
      if ((bool) (Object) staticBatchRoot)
      {
        matrix4x4 = staticBatchRoot.transform.worldToLocalMatrix;
        staticBatchRootTransform = staticBatchRoot.transform;
      }
      int batchIndex = 0;
      int num1 = 0;
      List<MeshSubsetCombineUtility.MeshContainer> meshes = new List<MeshSubsetCombineUtility.MeshContainer>();
      using (StaticBatchingUtility.s_SortMarker.Auto())
        gos = InternalStaticBatchingUtility.SortGameObjectsForStaticBatching(gos, sorter ?? new InternalStaticBatchingUtility.StaticBatcherGOSorter());
      uint num2 = 0;
      bool flag = false;
      foreach (GameObject go in gos)
      {
        MeshFilter component1 = go.GetComponent(typeof (MeshFilter)) as MeshFilter;
        if (!((Object) component1 == (Object) null))
        {
          Mesh sharedMesh = component1.sharedMesh;
          if (!sharedMesh.IsCloudResource() && !((Object) sharedMesh == (Object) null) && (isEditorPostprocessScene || sharedMesh.canAccess) && StaticBatchingHelper.IsMeshBatchable(sharedMesh))
          {
            Renderer component2 = component1.GetComponent<Renderer>();
            if (!((Object) component2 == (Object) null) && component2.enabled && component2.staticBatchIndex == 0)
            {
              Material[] source = component2.sharedMaterials;
              if (!((IEnumerable<Material>) source).Any<Material>((Func<Material, bool>) (m => (Object) m != (Object) null && (Object) m.shader != (Object) null && m.shader.disableBatching != 0)))
              {
                int vertexCount = sharedMesh.vertexCount;
                if (vertexCount != 0)
                {
                  MeshRenderer meshRenderer = component2 as MeshRenderer;
                  if (!((Object) meshRenderer != (Object) null) || (!((Object) meshRenderer.additionalVertexStreams != (Object) null) || vertexCount == meshRenderer.additionalVertexStreams.vertexCount) && (!((Object) meshRenderer.enlightenVertexStream != (Object) null) || vertexCount == meshRenderer.enlightenVertexStream.vertexCount))
                  {
                    uint meshFormatHash = InternalStaticBatchingUtility.GetMeshFormatHash(sharedMesh);
                    bool scaleFlip = InternalStaticBatchingUtility.StaticBatcherGOSorter.GetScaleFlip(go);
                    if (num1 + vertexCount > 64000 || (int) meshFormatHash != (int) num2 || scaleFlip != flag)
                    {
                      InternalStaticBatchingUtility.MakeBatch(meshes, staticBatchRootTransform, batchIndex++);
                      meshes.Clear();
                      num1 = 0;
                      flag = scaleFlip;
                    }
                    num2 = meshFormatHash;
                    MeshSubsetCombineUtility.MeshInstance meshInstance = new MeshSubsetCombineUtility.MeshInstance();
                    meshInstance.meshInstanceID = sharedMesh.GetInstanceID();
                    meshInstance.rendererInstanceID = component2.GetInstanceID();
                    if ((Object) meshRenderer != (Object) null)
                    {
                      if ((Object) meshRenderer.additionalVertexStreams != (Object) null)
                        meshInstance.additionalVertexStreamsMeshInstanceID = meshRenderer.additionalVertexStreams.GetInstanceID();
                      if ((Object) meshRenderer.enlightenVertexStream != (Object) null)
                        meshInstance.enlightenVertexStreamMeshInstanceID = meshRenderer.enlightenVertexStream.GetInstanceID();
                    }
                    meshInstance.transform = matrix4x4 * component1.transform.localToWorldMatrix;
                    meshInstance.lightmapScaleOffset = component2.lightmapScaleOffset;
                    meshInstance.realtimeLightmapScaleOffset = component2.realtimeLightmapScaleOffset;
                    MeshSubsetCombineUtility.MeshContainer meshContainer = new MeshSubsetCombineUtility.MeshContainer();
                    meshContainer.gameObject = go;
                    meshContainer.instance = meshInstance;
                    meshContainer.subMeshInstances = new List<MeshSubsetCombineUtility.SubMeshInstance>();
                    meshes.Add(meshContainer);
                    if (source.Length > sharedMesh.subMeshCount)
                    {
                      string[] strArray = new string[7]
                      {
                        "Mesh '",
                        sharedMesh.name,
                        "' has more materials (",
                        null,
                        null,
                        null,
                        null
                      };
                      int num3 = source.Length;
                      strArray[3] = num3.ToString();
                      strArray[4] = ") than subsets (";
                      num3 = sharedMesh.subMeshCount;
                      strArray[5] = num3.ToString();
                      strArray[6] = ")";
                      Debug.LogWarning((object) string.Concat(strArray), (Object) component2);
                      Material[] materialArray = new Material[sharedMesh.subMeshCount];
                      for (int index = 0; index < sharedMesh.subMeshCount; ++index)
                        materialArray[index] = component2.sharedMaterials[index];
                      component2.sharedMaterials = materialArray;
                      source = materialArray;
                    }
                    for (int index = 0; index < Math.Min(source.Length, sharedMesh.subMeshCount); ++index)
                      meshContainer.subMeshInstances.Add(new MeshSubsetCombineUtility.SubMeshInstance()
                      {
                        meshInstanceID = component1.sharedMesh.GetInstanceID(),
                        vertexOffset = num1,
                        subMeshIndex = index,
                        gameObjectInstanceID = go.GetInstanceID(),
                        transform = meshInstance.transform
                      });
                    num1 += sharedMesh.vertexCount;
                  }
                }
              }
            }
          }
        }
      }
      InternalStaticBatchingUtility.MakeBatch(meshes, staticBatchRootTransform, batchIndex);
    }

    private static void MakeBatch(
      List<MeshSubsetCombineUtility.MeshContainer> meshes,
      Transform staticBatchRootTransform,
      int batchIndex)
    {
      if (meshes.Count < 2)
        return;
      using (StaticBatchingUtility.s_MakeBatchMarker.Auto())
      {
        List<MeshSubsetCombineUtility.MeshInstance> meshInstanceList = new List<MeshSubsetCombineUtility.MeshInstance>();
        List<MeshSubsetCombineUtility.SubMeshInstance> subMeshInstanceList = new List<MeshSubsetCombineUtility.SubMeshInstance>();
        foreach (MeshSubsetCombineUtility.MeshContainer mesh in meshes)
        {
          meshInstanceList.Add(mesh.instance);
          subMeshInstanceList.AddRange((IEnumerable<MeshSubsetCombineUtility.SubMeshInstance>) mesh.subMeshInstances);
        }
        string meshName = "Combined Mesh" + " (root: " + ((Object) staticBatchRootTransform != (Object) null ? staticBatchRootTransform.name : "scene") + ")";
        if (batchIndex > 0)
          meshName = meshName + " " + (batchIndex + 1).ToString();
        Mesh combinedMesh = StaticBatchingHelper.InternalCombineVertices(meshInstanceList.ToArray(), meshName);
        StaticBatchingHelper.InternalCombineIndices(subMeshInstanceList.ToArray(), combinedMesh);
        int firstSubMesh = 0;
        foreach (MeshSubsetCombineUtility.MeshContainer mesh in meshes)
        {
          ((MeshFilter) mesh.gameObject.GetComponent(typeof (MeshFilter))).sharedMesh = combinedMesh;
          int count = mesh.subMeshInstances.Count;
          Renderer component = mesh.gameObject.GetComponent<Renderer>();
          component.SetStaticBatchInfo(firstSubMesh, count);
          component.staticBatchRootTransform = staticBatchRootTransform;
          component.enabled = false;
          component.enabled = true;
          MeshRenderer meshRenderer = component as MeshRenderer;
          if ((Object) meshRenderer != (Object) null)
          {
            meshRenderer.additionalVertexStreams = (Mesh) null;
            meshRenderer.enlightenVertexStream = (Mesh) null;
          }
          firstSubMesh += count;
        }
      }
    }

    public class StaticBatcherGOSorter
    {
      public virtual long GetMaterialId(Renderer renderer)
      {
        return (Object) renderer == (Object) null || (Object) renderer.sharedMaterial == (Object) null ? 0L : (long) renderer.sharedMaterial.GetInstanceID();
      }

      public int GetLightmapIndex(Renderer renderer)
      {
        return (Object) renderer == (Object) null ? -1 : renderer.lightmapIndex;
      }

      public static Renderer GetRenderer(GameObject go)
      {
        if ((Object) go == (Object) null)
          return (Renderer) null;
        MeshFilter component = go.GetComponent(typeof (MeshFilter)) as MeshFilter;
        return (Object) component == (Object) null ? (Renderer) null : component.GetComponent<Renderer>();
      }

      public static Mesh GetMesh(GameObject go)
      {
        if ((Object) go == (Object) null)
          return (Mesh) null;
        MeshFilter component = go.GetComponent<MeshFilter>();
        return (Object) component == (Object) null ? (Mesh) null : component.sharedMesh;
      }

      public virtual long GetRendererId(Renderer renderer)
      {
        return (Object) renderer == (Object) null ? -1L : (long) renderer.GetInstanceID();
      }

      public static bool GetScaleFlip(GameObject go)
      {
        return (double) go.transform.localToWorldMatrix.determinant < 0.0;
      }
    }
  }
}
